#include "cbusschedulerxmlreader.h"

CBusSchedulerXMLReader::CBusSchedulerXMLReader()
{
    myDocument = NULL;
    previousBus = NULL;
    previousStation = NULL;
}

CBusSchedulerXMLReader::~CBusSchedulerXMLReader()
{
    if(myDocument != NULL)
    {
        delete myDocument;
    }

    if(previousBus != NULL)
    {
        delete previousBus;
    }

    if(previousStation != NULL)
    {
        delete previousStation;
    }
}

bool CBusSchedulerXMLReader::LoadFile(const char *filename)
{
    // load file
    myDocument = new TiXmlDocument(filename);
    bool b = myDocument->LoadFile();
    if(!b)
    {
        return b;
    }

    // read BUSES tag
    RootElement = myDocument->RootElement();

    return b;
}

bool CBusSchedulerXMLReader::ReadFirstBus()
{
    TiXmlElement *currentBusLocal;
    currentBusLocal = RootElement->FirstChildElement();

    if(currentBusLocal == NULL)
    {
        return false;
    }
    else
    {
        //read bus info
        GetBusInfo(currentBusLocal, m_busName, m_interval, m_beginStation, m_endStation);

        previousBus = currentBusLocal;
        this->currentBus = currentBusLocal;
        return true;
    }
}

bool CBusSchedulerXMLReader::ReadNextBus()
{
    TiXmlElement *currentBusLocal = this->previousBus->NextSiblingElement();

    if(currentBusLocal == NULL)
    {
        return false;
    }
    else
    {
        //read bus info
        GetBusInfo(currentBusLocal, m_busName, m_interval, m_beginStation, m_endStation);

        previousBus = currentBusLocal;
        this->currentBus = currentBusLocal;
        return true;
    }
}

bool CBusSchedulerXMLReader::ReadFirstStation()
{
    TiXmlElement *currentStationLocal = this->currentBus->FirstChildElement();

    if(currentStationLocal == NULL)
    {
        return false;
    }
    else
    {
        //read station info
        GetStationInfo(currentStationLocal, m_stationName,\
                       m_seqStartToEnd, m_seqEndToStart,\
                       m_lat, m_lon,\
                       m_start2endFistTime, m_start2endLastTime,\
                       m_end2startFirstTime, m_end2startLastTime);

        previousStation = currentStationLocal;
        return true;
    }
}

bool CBusSchedulerXMLReader::ReadNextStation()
{
    TiXmlElement *currentStationLocal = this->previousStation->NextSiblingElement();

    if(currentStationLocal == NULL)
    {
        return false;
    }
    else
    {
        //read station info
        GetStationInfo(currentStationLocal, m_stationName,\
                       m_seqStartToEnd, m_seqEndToStart,\
                       m_lat, m_lon,\
                       m_start2endFistTime, m_start2endLastTime,\
                       m_end2startFirstTime, m_end2startLastTime);

        previousStation = currentStationLocal;
        return true;
    }
}

void CBusSchedulerXMLReader::GetBusInfo(TiXmlElement* element, QString& busName, int& interval,\
                                        QString& beginStation, QString &endStation)
{
    // get name attribute
    TiXmlAttribute *NameAttribute = element->FirstAttribute();
    busName = NameAttribute->Value();

    // get interval
    TiXmlAttribute *IntervalAttribute = NameAttribute->Next();
    interval = QString(IntervalAttribute->Value()).toInt();

    // get beginStation
    TiXmlAttribute *BeginAttribute = IntervalAttribute->Next();
    beginStation = BeginAttribute->Value();

    // get endStation
    TiXmlAttribute *EndAttribute = BeginAttribute->Next();
    endStation = EndAttribute->Value();
}

// note: the sequence must be aligned to the definition of the xml file
void CBusSchedulerXMLReader::GetStationInfo(TiXmlElement* element, QString& stationName,\
                                            int& seqStart2End, int& seqEnd2Start,\
                                            float& lat, float& lon,\
                                            int& start2endFirstTime, int&  start2endLastTime, \
                                            int& end2startFirstTime, int& end2startLastTime)
{
    // get name attribute
    TiXmlAttribute *NameAttribute = element->FirstAttribute();
    stationName = NameAttribute->Value();

    // get seq number from start to end
    TiXmlAttribute *SeqStart2EndAttribute = NameAttribute->Next();
    seqStart2End = QString(SeqStart2EndAttribute->Value()).toInt();

    // get seq number from end to start
    TiXmlAttribute *SeqEnd2StartAttribute = SeqStart2EndAttribute->Next();
    seqEnd2Start = QString(SeqEnd2StartAttribute->Value()).toInt();

    // get lat
    TiXmlAttribute *LatAttribute = SeqEnd2StartAttribute->Next();
    lat = QString(LatAttribute->Value()).toFloat();

    // get lon
    TiXmlAttribute *LonAttribute = LatAttribute->Next();
    lon = QString(LonAttribute->Value()).toFloat();

    // get start2endFistTime
    TiXmlAttribute *start2endFistTimeAttribute = LonAttribute->Next();
    start2endFirstTime = QString(start2endFistTimeAttribute->Value()).toInt();

    // get start2endLastTime
    TiXmlAttribute *start2endLastTimeAttribute = start2endFistTimeAttribute->Next();
    start2endLastTime = QString(start2endLastTimeAttribute->Value()).toInt();

    // get end2startFirstTime
    TiXmlAttribute *end2startFirstTimeAttribute = start2endLastTimeAttribute->Next();
    end2startFirstTime = QString(end2startFirstTimeAttribute->Value()).toInt();

    // get end2startLastTime
    TiXmlAttribute *end2startLastTimeAttribute = end2startFirstTimeAttribute->Next();
    end2startLastTime = QString(end2startLastTimeAttribute->Value()).toInt();
}

// this funciton will read the xml file and generate the hash table for the bus station
// and generate all the stations mapping for the bus
void CBusSchedulerXMLReader::GenerateIntermediaResult()
{
    assert(myDocument != NULL);

    vector<BUS_INFO_NAME_BASED> vecBusInfo;
    BUS_INFO_NAME_BASED busInfoNameBased;

    if (this->ReadFirstBus())
    {
        // we have the first bus info
        busInfoNameBased.busName = m_busName;
        busInfoNameBased.startStation = m_beginStation;
        busInfoNameBased.endStation = m_endStation;
        busInfoNameBased.interval = m_interval;

        // try to read all the stations info
        if(this->ReadFirstStation())
        {
            // we have the first station
            busInfoNameBased.stationName = m_stationName;
            m_stationMap.insert(m_stationName,
                                 BUS_INFO_STATION_BASED(m_beginStation, m_endStation, \
                                                   m_busName, m_interval,\
                                                   m_seqStartToEnd, m_start2endFistTime, m_start2endLastTime,\
                                                   m_seqEndToStart, m_end2startFirstTime, m_end2startLastTime));

            // store bus info
            busInfoNameBased.firstTimeEnd2Start = m_end2startFirstTime;
            busInfoNameBased.lastTimeEnd2Start = m_end2startLastTime;
            busInfoNameBased.firstTimeStart2End = m_start2endFistTime;
            busInfoNameBased.lastTimeStart2End = m_start2endLastTime;

            //insert into vector
            vecBusInfo.push_back(busInfoNameBased);

            while(this->ReadNextStation())
            {
                // we have the next station info
                busInfoNameBased.stationName = m_stationName;
                m_stationMap.insert(m_stationName,
                                     BUS_INFO_STATION_BASED(m_beginStation, m_endStation, \
                                                       m_busName, m_interval,\
                                                       m_seqStartToEnd, m_start2endFistTime, m_start2endLastTime,\
                                                       m_seqEndToStart, m_end2startFirstTime, m_end2startLastTime));

                // store bus info
                busInfoNameBased.firstTimeEnd2Start = m_end2startFirstTime;
                busInfoNameBased.lastTimeEnd2Start = m_end2startLastTime;
                busInfoNameBased.firstTimeStart2End = m_start2endFistTime;
                busInfoNameBased.lastTimeStart2End = m_start2endLastTime;

                //insert into vector
                vecBusInfo.push_back(busInfoNameBased);
            }
        }

        // store info of the first bus
        m_busMap.insert(m_busName, vecBusInfo);

        // clear the vector
        vecBusInfo.clear();

        // check whether has other bus
        while(this->ReadNextBus())
        {
            // we have the current bus info
            busInfoNameBased.busName = m_busName;
            busInfoNameBased.startStation = m_beginStation;
            busInfoNameBased.endStation = m_endStation;
            busInfoNameBased.interval = m_interval;

            if(this->ReadFirstStation())
            {
                // we have the first station
                busInfoNameBased.stationName = m_stationName;
                m_stationMap.insert(m_stationName,
                                     BUS_INFO_STATION_BASED(m_beginStation, m_endStation, \
                                                       m_busName, m_interval,\
                                                       m_seqStartToEnd, m_start2endFistTime, m_start2endLastTime,\
                                                       m_seqEndToStart, m_end2startFirstTime, m_end2startLastTime));

                // store station info
                busInfoNameBased.firstTimeEnd2Start = m_end2startFirstTime;
                busInfoNameBased.lastTimeEnd2Start = m_end2startLastTime;
                busInfoNameBased.firstTimeStart2End = m_start2endFistTime;
                busInfoNameBased.lastTimeStart2End = m_start2endLastTime;

                //insert into vector
                vecBusInfo.push_back(busInfoNameBased);

                //check whether we have the next station
                while(this->ReadNextStation())
                {
                    // we have the next station
                    busInfoNameBased.stationName = m_stationName;
                    m_stationMap.insert(m_stationName,
                                         BUS_INFO_STATION_BASED(m_beginStation, m_endStation, \
                                                           m_busName, m_interval,\
                                                           m_seqStartToEnd, m_start2endFistTime, m_start2endLastTime,\
                                                           m_seqEndToStart, m_end2startFirstTime, m_end2startLastTime));
                    // store station info
                    busInfoNameBased.firstTimeEnd2Start = m_end2startFirstTime;
                    busInfoNameBased.lastTimeEnd2Start = m_end2startLastTime;
                    busInfoNameBased.firstTimeStart2End = m_start2endFistTime;
                    busInfoNameBased.lastTimeStart2End = m_start2endLastTime;

                    //insert into vector
                    vecBusInfo.push_back(busInfoNameBased);
                }
            }

            // store info from the first bus
            m_busMap.insert(m_busName, vecBusInfo);

            // clear the vector
            vecBusInfo.clear();
        }
    }
}
